/*********************************************************************************
Organization 					: 				Georgia Institute of Technology
  
Institute 						:				Cognitive Computing Group(CCL)
 
Authors							: 				Manish Mehta 
 												
Class							:				TraceHelpers
 
Function						: 				A helper class for extracting information 
												frome the trace
****************************************************************************/


package behavioradaptation.reasoner;

import org.w3c.dom.Node;

import planninglanguage.goals.Goal;
import planninglanguage.plans.BasicOperatorPlan;
import planninglanguage.plans.MultiPlan;
import planninglanguage.plans.ParallelPlan;
import planninglanguage.plans.Plan;
import planninglanguage.plans.SequentialPlan;
import planninglanguage.plans.SubGoalPlan;
import trace.Entry;
import trace.Trace;
import base.WargusGameState;
import behavioradaptation.analysisdata.SubGoalData;
import cbr.CBR;
import cbr.episodicCBR.CaseBaseBehavior;
import cbr.episodicCBR.EpisodicCBR;


public class TraceHelpers {

	public static SubGoalData getSubGoalData(Plan pl, Trace a_trace, EpisodicCBR cbr)
	{
	
		Plan plan = getParentSubGoal(pl);
		CaseBaseBehavior a_cbo = null;
		if(plan == null)
			return null;
		SubGoalData sgd = new SubGoalData();
		Goal g = ((SubGoalPlan)plan).getGoal();
		String st = g.getClass().getName();
		sgd.m_sgp = (SubGoalPlan)plan;
		sgd.m_gname = st;
		WargusGameState game_state = a_trace.getGameStateCBRIndex(g.getClass().getName());
		sgd.m_gamestate = game_state; 
		try {
				a_cbo = cbr.retrieveCaseBehavior(g, game_state);
			} catch (Exception e2) {
			e2.printStackTrace();
		}
		sgd.cbo = a_cbo;	
		return sgd;
		
	}
	
	/*
	 * Get the parent subgoal that was executing for a plan
	 */
	public static Plan getParentSubGoal(Plan plan)
	{
		Plan pl = plan;
		while(true)
		{	
			if(pl.getParent() == null)
				return null; 
			else if(pl.getParent() instanceof SubGoalPlan)
				return pl.getParent();
			else 
				pl = pl.getParent();
		}	
	}
	/*
	 * Check whether Plan a_plan is parent of plan "a"
	 */
	public static boolean isChildofPlan(Plan a_plan, Plan a)
	{
		String planType = a_plan.getClass().getName();
		
		if(planType.equals("planninglanguage.plans.SubGoalPlan")) {
			SubGoalPlan p=(SubGoalPlan)a_plan;
			if (p.getPlan()!=null) {
				if (p.getPlan() == a) {
					return true;
				} else {
					return isChildofPlan(p.getPlan(),a);
				}
			}	
		} else if(planType.equals("planninglanguage.plans.ParallelPlan")) {
			MultiPlan p=(MultiPlan)a_plan;
			for(Plan p2 : p) {
				if (p2!=a) 
				{
					boolean ischild = isChildofPlan(p2,a);
					if(ischild)
						return true;
				}
			}
			if (p.contains(a)) 
				return true;
			else
				return false;
			
		} else if(planType.equals("planninglanguage.plans.SequentialPlan")) {
			MultiPlan p=(MultiPlan)a_plan;
			for(Plan p2 : p) {
				if (p2!=a)
				{	
					boolean ischild = isChildofPlan(p2,a);
					if(ischild)
						return true;
				}
				
			}
			if (p.contains(a)) 
				return true;
			else
				return false;
		}else{
			if(a_plan == a)
				return true;
			else
				return false;
		}
			
		return false;
	}
	/*
	 * for given plan "a_plan" and plan "b" find the matching plan "a"
	 * that is part of a_plan within plan "b"
	 */
	public static void getModifiedPlan(Plan a_plan, Plan b, Plan a, boolean replaced)
	{
		String planType = a_plan.getClass().getName();
		
		if(planType.equals("planninglanguage.plans.SubGoalPlan")) {
			SubGoalPlan p=(SubGoalPlan)a_plan;
			if (p.getPlan()!=null) {
				if (p.getPlan() == a) {
					p.setPlan(b);
				} else {
					getModifiedPlan(p.getPlan(),b, a, replaced);
				}
			}	
		} else if(planType.equals("planninglanguage.plans.ParallelPlan")) {
			MultiPlan p=(MultiPlan)a_plan;
			for(Plan p2 : p) {
				if (p2!=a) getModifiedPlan(p2,b,a, replaced);
			}
			if (p.contains(a)) {
				if(replaced)
					p.set(p.indexOf(a), b);
				else
					p.add(p.indexOf(a), b);
			}
		} else if(planType.equals("planninglanguage.plans.SequentialPlan")) {
			MultiPlan p=(MultiPlan)a_plan;
			for(Plan p2:p) {
				if (p2!=a) getModifiedPlan(p2,b,a, replaced);
			}
			if (p.contains(a)) {
				if(replaced)
					p.set(p.indexOf(a), b);
				else
					p.add(p.indexOf(a), b);
			}
		}
	}
	public static Plan cloneEntry(Plan p) throws CloneNotSupportedException
	{
		if(p instanceof BasicOperatorPlan)
		{
//			System.out.println("Hello");
			SubGoalPlan sgp = (SubGoalPlan)TraceHelpers.getParentSubGoal(p);
			SubGoalPlan sgpcloned = (SubGoalPlan)sgp.clone();
			return findClonedNode(sgp, sgpcloned, p);
		}
		else
			return p;
		
	}
	/*
	 * Clone the Node and find the corresponding plan n1 in plan r1
	 */
	public static Plan findClonedNode(Plan r1,Plan r2,Plan n1)
	{
		if (r1 == n1) return r2;
		
		if (r1 instanceof SubGoalPlan &&
			r2 instanceof SubGoalPlan) {
			SubGoalPlan sg1,sg2;
			
			sg1 = (SubGoalPlan)r1;
			sg2 = (SubGoalPlan)r2;
			
			if (sg1.getPlan()!=null && sg2.getPlan()!=null) {
				return findClonedNode(sg1.getPlan(),sg2.getPlan(),n1);
			}
		} else if (r1 instanceof SequentialPlan &&
				   r2 instanceof SequentialPlan) {
			MultiPlan sp1,sp2;
			
			sp1 = (MultiPlan)r1;
			sp2 = (MultiPlan)r2;
			
			for(int i=0;i<sp1.size();i++) {
				Plan p = findClonedNode(sp1.get(i),
										sp2.get(i),
										n1);
				if (p!=null) return p;
			}			
		} else if (r1 instanceof ParallelPlan &&
				   r2 instanceof ParallelPlan) {
			MultiPlan sp1,sp2;
			
			sp1 = (MultiPlan)r1;
			sp2 = (MultiPlan)r2;
			
			for(int i=0;i<sp1.size();i++) {
				Plan p = findClonedNode(sp1.get(i),
										sp2.get(i),
										n1);
				if (p!=null) return p;
			}
		}
		return null;
	}
	/*
	 * Modify the case base appropriately
	 */
	public static void modifyCaseBase(Plan plan, Trace a_trace, Plan rbplan, Entry entry, boolean replaced,  EpisodicCBR cbr)
	{
		Plan parent = plan.getParent();
		System.out.println("Parent is " + parent);
		SubGoalData sgd = getSubGoalData(plan, a_trace, cbr);
		CaseBaseBehavior cbo = sgd.cbo;
		CaseBaseBehavior ncbo = null;
		WargusGameState game_state = null;
		// If we havent already modified the Case then use the existing case
		// otherwise create a new case to modify it 
		if((cbo != null) && cbo.getModified())
		{
			Plan cboplan = cbo.getPlan();
			Plan tobereplaced =  findClonedNode(sgd.m_sgp.getPlan(), cboplan, plan);
			Reasoner.logger.println("OriginalPlan is :" + cbo.getPlan());
			TraceHelpers.getModifiedPlan(cbo.getPlan(), rbplan, tobereplaced, replaced);										
			Reasoner.logger.println("ModifiedPlan is :" + cbo.getPlan());
	//		CaseBase.setContext(cbo.getPlan(), cbo);
		}	
		// create a new case to modify it 	
		else
		{
			SubGoalPlan pl = sgd.m_sgp;
			if(pl != null)
			{	
//				Reasoner.logger.println("SubgoalPlan is :" + pl);	
				Reasoner.logger.println("OriginalPlan is :" + pl.getPlan());				
				TraceHelpers.getModifiedPlan(pl, rbplan, entry.getPlan(), replaced);
				Reasoner.logger.println("ModifiedPlan is :" + pl.getPlan());
				game_state = sgd.m_gamestate;
				// TODO: modify the string to be unique every time
				ncbo = cbr.createCaseBaseBehavior(game_state,cbo, pl.getPlan(), "behaviorModified");
				cbr.addCaseBaseBehavior(ncbo);
				ncbo.setModified(true);
			}	
		}
	}

}
